package com.sinovatech.ologger.actionlog.core;

import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import ognl.Ognl;
import ognl.OgnlException;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.sinovatech.ologger.actionlog.aop.annotation.OperationLogAnnotation;
import com.sinovatech.ologger.actionlog.aop.annotation.PassLogMethod;
import com.sinovatech.ologger.actionlog.converters.LogConverter;
import com.sinovatech.ologger.actionlog.entity.OperationLog;
import com.sinovatech.ologger.core.util.UserSession;
import com.sinovatech.ologger.util.LogUtil;
import com.sinovatech.ologger.util.StringHelper;

/**
 * 日志辅助类
 * @author nanquan
 *
 */
public class LogHelper {

	private static final Log logger = LogFactory.getLog(LogHelper.class);

	public static final String LOG_USER = "logUser";
	public static final String LOG_OPCMAP = "operationConditionsMap";
	public static final String COLON = ":";
	public static final String SEPARATED_COMMA = ",";
	private static final String ARGS_REGEX = "\\{([\\S&&[^\\}]]*args[\\.\\[]?[\\S&&[^\\}]]*)\\}";//"\\{(args[\\.\\[][\\S&&[^\\}]]*)\\}";
	private static final String OBJECT_REGEX = "\\{([\\S&&[^\\}]]*obj[\\.\\[]?[\\S&&[^\\}]]*)\\}";
	private static final String VAR_REGEX = "\\{([\\w:]+)\\}";
	private static final String FILE_REGEX = "(\\[[\\S\\s]*\\])";
	public static final String VAR_ARGS = "args";//ognl表达式中的方法参数
	public static final String VAR_RETURN = "returnValue";//ognl表达式中的返回值
	public static final String VAR_OBJECT = "obj";//ognl表达式中的实体对象
	private static Map<String, OperationLogAnnotation> operationLogConfigMap = new HashMap<String, OperationLogAnnotation>();
	/**
	 * 注册的日志转换器
	 */
	private final static Map<String, LogConverter> logConverters = new HashMap<String, LogConverter>();
	/**
	 * 检查方法返回成功的默认表达式
	 */
	public final static List<String> defaultSucessReturns = new ArrayList<String>();//默认成功的返回值表达式

	public static final String VAR_STAFFNAME = "staffName";

	/**
	 * 向当前ThreadLocal里放入logUser
	 * @param user
	 */
	public static void setUser(LogUser user) {
		UserSession.set(LOG_USER, user);
	}

	/**
	 * 从当前ThreadLocal里获取logUser
	 * @return
	 */
	public static LogUser getUser() {
		return (LogUser) UserSession.get(LOG_USER);
	}

	/**
	 * 判断此方法是否有过滤标识
	 * @param method
	 * @return
	 */
	public static boolean isPassMethod(Method method) {
		return method.getAnnotation(PassLogMethod.class) != null;
	}

	static {
		/**
		 * 默认检查成功的表达式
		 */
		defaultSucessReturns.add(VAR_RETURN + " == 1");
		defaultSucessReturns.add(VAR_RETURN + ".equals(\"1\") ");
	}

	/**
	 * 通过带变量的日志详细信息返回填充值之后的信息
	 * @param operationDetails
	 * @param opcMap
	 * @param conditionsJSON
	 * @return
	 */
	public static String processOperationDetails(String operationDetails, Map<String, Object> opcMap, String conditionsJSON) {
		String regex = "\\{(\\w+)\\}";//([\\d\\.]+) w:字母数字或_
		Matcher matcher = Pattern.compile(regex).matcher(operationDetails);
		while (matcher.find()) {
			String key = matcher.group(1);
			String value = null;
			if (opcMap != null && opcMap.get(key) != null) {
				value = opcMap.get(key).toString();
			} else if (!StringHelper.isEmpty(conditionsJSON)) {
				value = findAttributeValueFromJSON(conditionsJSON, key);
			}
			if (!StringHelper.isEmpty(value)) {
				operationDetails = operationDetails.replace("{" + key + "}", value);
			}
		}
		return operationDetails;
	}

	/**
	 * 通过属性名获取JSON字符串中的值
	 * 只匹配第一个符合的属性
	 * @param jsonStr
	 * @param attribute
	 * @return
	 */
	public static String findAttributeValueFromJSON(String jsonStr, String attribute) {
		String regex = "[\\s\\,\\[\\{\"']" + attribute + "\"?'?\\s*:\\s*\"?'?([\\S&&[^\\,\\]\\}\"']]+)";// 查找json里userName属性
		Matcher matcher = Pattern.compile(regex).matcher(jsonStr);
		while (matcher.find()) {
			if (!StringHelper.isEmpty(matcher.group(1))) {
				return matcher.group(1);
			}
		}
		return null;
	}

	/**
	 * 添加日志变量 通过ThreadLocal向当前线程添加
	 * 一般用于ajax删除操作时进行,因为后处理有可能实体已经不存在,而无法获取相关信息,所以在方法执行时就可以手动调用该方法,条件相关信息
	 * @param key
	 * @param value
	 */
	public static void addOperationConditions(String key, Object value) {
		getOpcMap().put(key, value);
	}

	/**
	 * 追加日志变量 通过ThreadLocal向当前线程添加
	 * 如果需要设定的变量包含多个值,可以用该方法追加
	 * @param key
	 * @param value
	 */
	public static void appOperationConditions(String key, Object value) {
		Object object = getOpcMap().get(key);
		value = value == null ? "" : value;
		if (object == null) {
			getOpcMap().put(key, value);
		} else {
			getOpcMap().put(key, object + OperationLog.SEPARATOR_VALUES + value);
		}
	}

	/**
	 * 通过ThreadLocal获取当前线程中的日志表量
	 */
	@SuppressWarnings("unchecked")
	public static Map<String, Object> getOpcMap() {
		Map<String, Object> opcMap = (Map<String, Object>) UserSession.get(LOG_OPCMAP);
		if (opcMap == null) {
			opcMap = new HashMap<String, Object>();
			UserSession.set(LOG_OPCMAP, opcMap);
		}
		return opcMap;
	}

	public static Map<String, OperationLogAnnotation> getOperationLogConfigMap() {
		return operationLogConfigMap;
	}

	/**
	 * 通过日志详细信息(带表达式) 获取其中的args表达式
	 * @param operationDetails
	 * @return
	 */
	public static List<String> findArgsExpression(String operationDetails) {
		return findExpressionByRegex(ARGS_REGEX, operationDetails);
	}

	/**
	 * 通过指定正则规则在text中获取符号条件的字符串集合
	 * @param regex 正则表达式
	 * @param text 目标字符串
	 * @return
	 */
	public static List<String> findExpressionByRegex(String regex, String text) {
		List<String> exp = new ArrayList<String>();
		Matcher matcher = Pattern.compile(regex).matcher(text);
		while (matcher.find()) {
			exp.add((matcher.group(1)));
		}
		return exp;
	}

	/**
	 * 获取{变量名}格式的变量
	 * 变量名为 字母、数字、_或者:
	 * @param exp
	 * @return
	 */
	public static List<String> findVarExpression(String exp) {
		return findExpressionByRegex(VAR_REGEX, exp);
	}

	/**
	 * 通过日志详细信息(带表达式) 获取其中的args表达式
	 * @param operationDetails
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static String processOperationDetailsWithArgs(String operationDetails, Object[] args) {
		try {
			List<String> argsExpression = findArgsExpression(operationDetails);
			Map ognlMap = new HashMap();
			ognlMap.put(VAR_ARGS, args);
			for (String key : argsExpression) {
				try {
					if (key.indexOf(COLON) > 0) {//带预定处理表达式
						operationDetails = processConvertExpression(operationDetails, ognlMap, key);
					} else {
						Object parseExpression = Ognl.parseExpression(key);
						Object value = Ognl.getValue(parseExpression, ognlMap);
						if (value != null) {
							operationDetails = operationDetails.replace("{" + key + "}", value.toString());
						}
					}
				} catch (OgnlException e) {
					logger.error(LogUtil.stackTraceToString(e));
				}
			}
		} catch (Exception e) {
			logger.error(LogUtil.stackTraceToString(e));
		}
		return operationDetails;
	}

	@SuppressWarnings("unchecked")
	private static String processConvertExpression(String operationDetails, Map ognlMap, String key) throws OgnlException {
		String[] strings = key.split(COLON);
		if (!ArrayUtils.isEmpty(strings) && strings.length >= 2) {
			Object parseExpression = Ognl.parseExpression(strings[1]);
			Object value = Ognl.getValue(parseExpression, ognlMap);
			String convert = convertWithLogConverter(strings[0], value);
			if (convert != null) {
				operationDetails = operationDetails.replace("{" + key + "}", convert);
			}
		}
		return operationDetails;
	}

	/**
	 * 判断返回值与指定值是否相等
	 * 参数皆可为空
	 * @param returnValue
	 * @param targetValue
	 * @return
	 */
	public static boolean returnValueEq(Object returnValue, Object targetValue) {
		return ObjectUtils.equals(returnValue, targetValue);
	}

	/**
	 * 通过未知类型 获取list集合的id
	 * @param obj
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static List<Serializable> convertObjectToListIds(Object obj) {
		List<Serializable> list = new ArrayList<Serializable>();
		if (obj != null) {
			if (obj instanceof Long[] || obj instanceof long[]) {
				Long[] ids = obj instanceof Long[] ? (Long[]) obj : ArrayUtils.toObject((long[]) obj);
				for (Long id : ids) {
					list.add((Long) id);
				}
			} else if (obj instanceof Long) {
				Long id = (Long) obj;
				list.add(id);
			} else if (obj instanceof Integer[] || obj instanceof int[]) {
				Integer[] ids = obj instanceof Integer[] ? (Integer[]) obj : ArrayUtils.toObject((int[]) obj);
				for (Integer id : ids) {
					list.add((Integer) id);
				}
			} else if (obj instanceof Integer) {
				Integer id = (Integer) obj;
				list.add(id);
			} else if (obj instanceof Object[]) {
				Serializable[] ids = (Serializable[]) obj;
				for (Serializable id : ids) {
					list.add(id.toString());
				}
			} else if (obj instanceof String) {
				String[] ids = obj.toString().split(",");
				for (String id : ids) {
					list.add(Long.valueOf(id));
				}
			} else if (obj instanceof List) {
				list.addAll((Collection<? extends Serializable>) obj);
			} else {
				list.add((Serializable) obj);
			}
		}
		return list;
	}

	/**
	 * 注册转换器
	 * @param converter
	 * @param name
	 */
	public static void registerLogConverter(LogConverter converter, String name) {
		logConverters.put(name, converter);
	}

	/**
	 * 获取转换器对象
	 * @param name
	 * @return
	 */
	public static LogConverter getLogConverter(String name) {
		return logConverters.get(name);
	}

	/**
	 * 调用指定转换器获取数据
	 * @param name 转换器名称
	 * @param obj 要转换的目标对象
	 * @return 转换结果
	 */
	public static String convertWithLogConverter(String name, Object obj) {
		LogConverter logConverter = getLogConverter(name);
		if (logConverter != null) {
			return logConverter.convert(obj);
		}
		return "";
	}

	@SuppressWarnings("unchecked")
	public static void processEntityListWithExpression(List<?> entitys, String entityExpression, OperationLog log) {
		entityExpression = StringHelper.isEmpty(entityExpression) ? log.getOperationDetails() : entityExpression;
		Map ognlMap = new HashMap();
		List<String> objExps = findExpressionByRegex(OBJECT_REGEX, entityExpression);
		if (CollectionUtils.isEmpty(entitys) || CollectionUtils.isEmpty(objExps)) {
			return;
		}
		log.setOperationDetails("");
		for (Object obj : entitys) {
			ognlMap.put(VAR_OBJECT, obj);
			String entityDetails = entityExpression;
			for (String exp : objExps) {
				Object parseExpression;
				try {
					if (exp.indexOf(COLON) > 0) {//带预定处理表达式
						entityDetails = processConvertExpression(entityDetails, ognlMap, exp);
					} else {
						parseExpression = Ognl.parseExpression(exp);
						Object value = Ognl.getValue(parseExpression, ognlMap);
						entityDetails = entityDetails.replace("{" + exp + "}", value != null ? value.toString() : "");
					}
				} catch (OgnlException e) {
					logger.error(LogUtil.stackTraceToString(e));
				}
			}
			log.appendOperationDetails(entityDetails).append(OperationLog.SEPARATOR_GROUP);
		}
		log.getOperationDetailsBuilder().deleteCharAt(log.getOperationDetailsBuilder().length() - 1);
	}

	/**
	 * 返回 上传的文件信息
	 * @param text
	 * @return 0:原始文件名(包括扩展名) 1:web路径  2：本地路径
	 */
	public static String[] getUploadFileInfo(String text) {
		List<String> list = findExpressionByRegex(FILE_REGEX, text);
		return list.size() > 0 && !StringHelper.isEmpty(list.get(0)) ? list.get(0).replace("[", "").replace("]", "").split(SEPARATED_COMMA) : null;
	}

	/**
	 * 替换文件信息字符串
	 * @param text
	 * @param replaceStr
	 * @return
	 */
	public static String processUploadFileInfo(String text, String replaceStr) {
		List<String> list = findExpressionByRegex(FILE_REGEX, text);
		return list.size() > 0 && !StringHelper.isEmpty(list.get(0)) ? text.replace(list.get(0), replaceStr) : null;
	}

}
